/*
 * @Author: asushiye
 * @Date: 2020-07-07 09:41:13
 * @Commit:  用于上传和下载服务端文件file
 * 安装"file-saver": "^2.0.5",
 * npm install @types/file-saver --save-dev
 * npm install file-saver --save
 */
import { HttpClient, HttpEventType, HttpRequest, HttpResponse, HttpHeaders } from '@angular/common/http';
import { ChangeDetectorRef, Injectable, Injector } from '@angular/core';
import { XlsxService } from '@delon/abc/xlsx';
// import { saveAs } from 'file-saver';
import type { NzSafeAny } from 'ng-zorro-antd/core/types';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { of } from 'rxjs';

import { AfMessageService } from './af-message.service';

@Injectable({
  providedIn: 'root'
})
export class AfUpDownService {
  constructor(
    private http: HttpClient,
    private injector: Injector,
    private msgSrv: AfMessageService,
    private xlsx: XlsxService // private cdr: ChangeDetectorRef
  ) {}

  public get notification(): NzNotificationService {
    return this.injector.get(NzNotificationService);
  }

  // 上传文件进度
  public uploadProgress: number = 0;

  // 不推荐使用， 原因如果使用代理方式来访问，url地址就不对了
  public windowOpen(url: any) {
    window.open(url);
  }

  // 使用第三方控件file_saver来实现
  // public downFile(httpMethod: string, httpUrl: any, httpParams: any, httpBody: any) {
  //   this.http
  //     .request(httpMethod, httpUrl, {
  //       params: httpParams || {},
  //       responseType: 'blob',
  //       observe: 'response',
  //       body: httpBody
  //     })
  //     .subscribe({
  //       next: (res: HttpResponse<Blob>) => {
  //         if (res.status !== 200 || res.body!.size <= 0) {
  //           this.msgSrv.msg_warning('下载异常， 请稍后重试');
  //           return;
  //         }
  //         const disposition = this.getDisposition(res.headers.get('content-disposition'));
  //         let fileName =
  //           disposition[`filename*`] || disposition[`filename`] || res.headers.get('filename') || res.headers.get('x-filename');
  //         if (!fileName) {
  //           fileName = '下载异常';
  //         }
  //         saveAs(res.body!, decodeURI(fileName as string));
  //       },
  //       error: err => this.msgSrv.msg_warning(`下载异常: ${err}`)
  //     });
  // }

  // 推荐使用
  public downFile(httpMethod: string, httpUrl: any, httpParams: any, httpBody: any) {
    this.http
      .request(httpMethod, httpUrl, {
        params: httpParams || {},
        responseType: 'blob',
        observe: 'response',
        body: httpBody
      })
      .subscribe({
        next: (res: HttpResponse<Blob>) => {
          if (res.status !== 200 || res.body!.size <= 0) {
            this.msgSrv.msg_warning('下载异常， 请稍后重试');
            return;
          }
          const disposition = this.getDisposition(res.headers.get('content-disposition'));
          console.log(JSON.stringify(disposition));
          let fileName =
            disposition[`filename*`] || disposition[`filename`] || res.headers.get('filename') || res.headers.get('x-filename');
          if (!fileName) {
            fileName = '下载异常';
          }

          const blob = res.body as Blob;
          const objectURL = window.URL.createObjectURL(blob);
          const a = document.createElement('a');
          a.href = objectURL;
          a.download = fileName; // 此处的savedName为保存到本地的文件名称及后缀
          a.click();
          // 释放已创建的URL对象
          window.URL.revokeObjectURL(objectURL);
        },
        error: err => this.msgSrv.msg_warning(`下载异常: ${err}`)
      });
  }

  // attachment; filename=常用命令收集_20231026140340.md
  // 转换为：{"filename":"常用命令收集_20231026140340.md"}
  private getDisposition(data: string | null): NzSafeAny {
    if (data == null) {
      return '';
    }
    data = decodeURIComponent(data);
    const arr: Array<Record<string, string>> = (data || '')
      .split(';')
      .filter(i => i.includes('='))
      .map(v => {
        const strArr = v.split('=');
        const utfId = `UTF-8''`;
        let value = strArr[1];
        if (value.startsWith(utfId)) value = value.substring(utfId.length);
        return { [strArr[0].trim()]: value };
      });
    return arr.reduce((_o, item) => item, {});
  }

  // 导出到excel文件
  exportXlsx(format: 'xlsx' | 'csv', table: any, sheetName: any, fileName?: string) {
    this.xlsx.export({
      sheets: [
        {
          data: table,
          name: sheetName
        }
      ],
      filename: fileName,
      format: format
    });
  }

  importXlsx(fileOrUrl: File | string) {
    return this.xlsx.import(fileOrUrl);
  }

  // 下载文件method POST, GET
  downLoadFile(method: string, url: string, body: any) {
    const req = new HttpRequest(method, url, body, {
      reportProgress: true,
      responseType: 'blob'
    });

    this.uploadProgress = 0;
    return this.http.request(req);
  }

  // 下载文件
  downLoadFile2(url: string) {
    // 打开新窗口方式进行下载
    window.open(url);
  }

  /**
   * 文件下载
   *
   * @param url 下载URL，【该URL需要加入到拦截器的白名单中】
   * @param fileName 存储在本地的文件名称加后缀
   * @param paramsObj 接口参数对象
   */
  downFileForGet(url: string, fileName: string, params: any) {
    this.http
      .get(url, {
        responseType: 'blob',
        params: params,
        headers: new HttpHeaders({
          'Content-Type': 'application/json'
        })
      })
      .subscribe(result => {
        const blob = new Blob([result], { type: 'application/octet-stream;charset=UTF-8' });
        // 创建一个URL对象
        const objectURL = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = objectURL;
        a.download = fileName; // 此处的savedName为保存到本地的文件名称及后缀
        a.click();
        // 释放已创建的URL对象
        window.URL.revokeObjectURL(objectURL);
      });
  }

  /**
   * 文件下载
   *
   * @param url 下载URL，【该URL需要加入到拦截器的白名单中】
   * @param fileName 存储在本地的文件名称加后缀
   * @param paramsObj 接口参数对象
   */
  downFileForPost(url: string, fileName: string, params: any) {
    this.http
      .post(url, params, {
        responseType: 'blob',
        headers: new HttpHeaders({
          'Content-Type': 'application/json'
        })
      })
      .subscribe(result => {
        const blob = new Blob([result], { type: 'application/octet-stream;charset=UTF-8' });
        // 创建一个URL对象
        const objectURL = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = objectURL;
        a.download = fileName; // 此处的savedName为保存到本地的文件名称及后缀
        a.click();
        // 释放已创建的URL对象
        window.URL.revokeObjectURL(objectURL);
      });
  }

  // 后端服务blob数据时，使用该方法保存文件
  saveFileFromBlob(data: any, fileName: any, fileType: any = 'xlsx') {
    let contentType = '';
    if (fileType === 'xlsx' || fileType === 'xls') {
      // 下载类型 xls
      contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
    } else {
      // 下载类型：csv
      contentType = 'text/csv';
    }
    const blob = new Blob([data], { type: contentType });
    const url = window.URL.createObjectURL(blob);

    // 以动态创建a标签进行下载
    const a = document.createElement('a');
    a.href = url;
    a.download = fileName;
    a.click();
    window.URL.revokeObjectURL(url);
  }
  // 上传单个文件， 按文件二进制上传
  uploadFileByArrayByte(url: string, file: any) {
    const req = new HttpRequest('POST', url, file, {
      reportProgress: true
    });

    this.uploadProgress = 0;
    return this.http.request(req);
  }

  // 上传单个文件, 按多部分媒体类型上，后台需要支持多部分
  uploadFileByMultPart(url: string, file: any) {
    const formData = new FormData();
    formData.append('file', file);

    const req = new HttpRequest('POST', url, formData, {
      reportProgress: true
    });

    this.uploadProgress = 0;
    return this.http.request(req);
  }

  // 上传多个文件, 按多部分媒体类型上，后台需要支持多部分和多文件
  uploadFilesByMultPart(url: string, files: any) {
    const formData = new FormData();
    const fileList: string[] = [];
    for (const file of files) {
      fileList.push(file.name);
      formData.append('file', file);
    }

    const req = new HttpRequest('POST', url, formData, {
      reportProgress: true
    });

    this.uploadProgress = 0;
    return this.http.request(req);
  }

  // 上传文件实例代码如下，可显示进度条，并处理http请求结果
  // submit(selected: any) {
  //   if (Array(selected.files).length <= 0) {
  //     return;
  //   }
  //   const url = this.codegen.getUploadUrl(this.record.title, this.record.business, this.form.controls.extendedFields.value);
  //   this.uploadProgress = 0;
  //   this.isLoading = true;
  //   try {
  //     const fileName = selected.files[0].name;
  //     this.updown.uploadFilesByMultPart(url, selected.files).subscribe((event) => {
  //       this.cdr.detectChanges();
  //       // this.uploadProgress = this.getEventMessage(event, selected.files[0]);
  //       switch (event.type) {
  //         case HttpEventType.Sent:
  //           this.msg.notice_info(`开始上传`, `${fileName}文件大小为${selected.files[0].size}`);
  //           return ;
  //         case HttpEventType.UploadProgress:
  //           if (event.total !== undefined) {
  //             this.uploadProgress = Math.round(100 * event.loaded / event.total);
  //           }
  //           this.msg.notice_info(`上传中`, `${fileName}文件${this.uploadProgress}% 已上传`);
  //           return ;
  //         case HttpEventType.Response:
  //           // completely uploaded
  //           if (event instanceof HttpResponse) {
  //             if (event.ok) {
  //               const body = event.body;
  //               if (body.status) {
  //                 this.msg.notice_info(`上传完成`, `${fileName}上传成功`);
  //                 this.modal.close('ok');
  //               } else {
  //                 if (body.code === -2) {
  //                   this.msg.notice_info(`文件已存在`,`若想上传, 可修改文件名或归档此文件`);
  //                   this.modal.close('exist');
  //                 } else {
  //                   this.msg.notice_info(`上传失败`,`网络不稳定，请稍后重试`);
  //                 }
  //               }
  //             }
  //           }
  //           return ;
  //         default:
  //           // other event.type
  //           this.msg.console_error(`File "${fileName}" surprising upload event: ${event.type}.`);
  //           return ;
  //       }
  //     });
  //   } finally {
  //     setTimeout(() => {
  //       this.isLoading = false;
  //       this.cdr.detectChanges();
  //     }, 100);
  //   }
  // }
}
